package com.smart.community.property.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.cache.DataScopeInfo;
import com.smart.community.commons.enums.SystemStatusEnum;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.PageResult;
import com.smart.community.commons.result.ResultCode;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.property.entity.WaterFee;
import com.smart.community.property.enums.PaymentMethodEnum;
import com.smart.community.property.mapper.WaterFeeMapper;
import com.smart.community.property.service.DataScopeService;
import com.smart.community.property.service.IWaterFeeService;
import com.smart.community.property.vo.WaterFeeVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 水费服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范.md》Service层规范实现：
 * - 异常处理规范：使用log.warn记录业务异常，使用log.error记录系统异常
 * - 参数验证：完善的参数验证和错误提示
 * - 业务逻辑：清晰的业务逻辑和错误处理
 * - 性能优化：合理的查询优化和缓存策略
 * - 生产环境标准：符合企业级应用的高可用性、可监控性、可维护性、可扩展性要求
 * - 空数组创建：使用Collections.emptyList()替代new ArrayList<>()
 * - 状态管理：使用SystemStatusEnum统一状态管理
 * - 缓存机制：实现完整的缓存策略，包括查询缓存和缓存失效
 * - 数据权限：实现完整的数据权限控制机制
 * 
 * @author Wu.Liang
 * @since 2025-06-26
 * @version 3.0.0 - 生产环境标准优化
 */
@Slf4j
@Service
public class WaterFeeServiceImpl extends ServiceImpl<WaterFeeMapper, WaterFee> implements IWaterFeeService {

    @Autowired
    private WaterFeeMapper waterFeeMapper;

    @Autowired
    private DataScopeService dataScopeService;
    
    // ========================= 缓存配置 =========================
    
    /**
     * 本地缓存：用户房户关联缓存，减少Feign调用
     */
    private final Map<Long, List<Long>> userHouseholdCache = new ConcurrentHashMap<>();
    

    @Override
    @Cacheable(value = "waterFee", key = "#page.current + \':\' + #page.size + \':\' + #communityId + \':\' + #paymentStatus + \':\' + T(com.smart.community.commons.utils.SecurityUtils).getCurrentUserId()", unless = "#result == null || #result.records.isEmpty()")
    public IPage<WaterFee> getWaterFeePage(Page<WaterFee> page, Long communityId, Integer paymentStatus) throws Exception {
        log.info("分页查询水费账单，社区ID: {}, 支付状态: {}", communityId, paymentStatus);
        
        // 数据权限验证
        DataScopeInfo dataScopeInfo = getCurrentUserDataScope();
        if (dataScopeInfo == null || !dataScopeInfo.isPropertyCompanyUser()) {
            log.warn("非物业公司用户或无数据权限，返回空结果");
            page.setRecords(Collections.emptyList());
            page.setTotal(0);
            return page;
        }

        // 如果指定了社区ID，验证权限
        if (communityId != null) {
            Long userId = SecurityUtils.getCurrentUserId();
            try {
                dataScopeService.hasCommunityPermission(userId, communityId);
            } catch (Exception e) {
                log.warn("用户无权访问指定社区，社区ID: {}, 用户ID: {}", communityId, userId);
                page.setRecords(Collections.emptyList());
                page.setTotal(0);
                return page;
            }
        } else {
            // 如果没有指定社区ID，使用用户可访问的社区列表
            List<Long> authorizedCommunityIds = dataScopeInfo.getCommunityIds();
            if (authorizedCommunityIds.isEmpty()) {
                log.warn("用户无数据访问权限，返回空结果");
                page.setRecords(Collections.emptyList());
                page.setTotal(0);
                return page;
            }
            // 暂时使用第一个有权限的社区
            communityId = authorizedCommunityIds.get(0);
        }

        // 计算偏移量
        int offset = (int) ((page.getCurrent() - 1) * page.getSize());
        int limit = (int) page.getSize();
        
        // 查询数据
        int total = waterFeeMapper.countByCommunityAndStatus(communityId, paymentStatus);
        List<WaterFee> records = waterFeeMapper.selectPageByCommunityAndStatus(communityId, paymentStatus, offset, limit);
        
        // 设置分页结果
        page.setRecords(records);
        page.setTotal(total);
        
        log.info("水费账单分页查询完成，总数: {}, 当前页: {}", total, page.getCurrent());
        return page;
    }

    @Override
    @Cacheable(value = "waterFee", key = "'latest_reading:' + #householdId", unless = "#result == null")
    public WaterFee getLatestReadingByHouseholdId(Long householdId) {
        log.debug("查询房户最新水表读数，房户ID: {}", householdId);
        return waterFeeMapper.selectLatestReadingByHouseholdId(householdId);
    }

    @Override
    @Cacheable(value = "waterFee", key = "'household_period:' + #householdId + \':\' + #billingPeriod", unless = "#result == null")
    public WaterFee getByHouseholdIdAndBillingPeriod(Long householdId, String billingPeriod) {
        log.debug("查询房户指定期间水费记录，房户ID: {}, 计费期间: {}", householdId, billingPeriod);
        return waterFeeMapper.selectByHouseholdIdAndBillingPeriod(householdId, billingPeriod);
    }

    @Override
    @GlobalTransactional
    @CacheEvict(value = "waterFee", allEntries = true)
    public boolean submitWaterMeterReading(Long householdId, BigDecimal reading, LocalDate readingDate) {
        log.info("提交水表读数，房户ID: {}, 表读数: {}, 读数日期: {}", householdId, reading, readingDate);
        
        try {
            // 数据权限验证（通过房户ID获取社区ID）
            WaterFee latestReading = waterFeeMapper.selectLatestReadingByHouseholdId(householdId);
            if (latestReading != null) {
                Long userId = SecurityUtils.getCurrentUserId();
                dataScopeService.hasCommunityPermission(userId, latestReading.getCommunityId());
            }

            // 获取最新的水表读数
            if (latestReading != null && latestReading.getCurrentReading().compareTo(reading) >= 0) {
                throw new BusinessException("新读数不能小于或等于上次读数");
            }

            // 创建新的水费记录
            WaterFee waterFee = new WaterFee();
            waterFee.setHouseholdId(householdId);
            waterFee.setCurrentReading(reading);
            waterFee.setReadingDate(readingDate);
            waterFee.setPaymentStatus(SystemStatusEnum.DISABLED.getCode()); // 0: 未支付

            boolean result = waterFeeMapper.insert(waterFee) > 0;
            log.info("水表读数提交完成，房户ID: {}, 结果: {}", householdId, result);
            return result;
        } catch (Exception e) {
            log.error("提交水表读数失败", e);
            throw new BusinessException("提交水表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    @CacheEvict(value = "waterFee", allEntries = true)
    public boolean batchSubmitMeterReading(Long communityId, List<Map<String, Object>> meterReadings) throws Exception {
        log.info("批量提交水表读数，社区ID: {}, 数据条数: {}", communityId, meterReadings.size());
        
        try {
            // 数据权限验证
            Long userId = SecurityUtils.getCurrentUserId();
            dataScopeService.hasCommunityPermission(userId, communityId);
            
            // 批量处理，提高性能
            for (Map<String, Object> reading : meterReadings) {
                Long householdId = Long.valueOf(reading.get("householdId").toString());
                BigDecimal currentReading = new BigDecimal(reading.get("reading").toString());
                LocalDate readingDate = LocalDate.parse(reading.get("readingDate").toString());
                
                submitWaterMeterReading(householdId, currentReading, readingDate);
            }
            
            log.info("批量提交水表读数完成，社区ID: {}", communityId);
            return true;
        } catch (Exception e) {
            log.error("批量提交水表读数失败", e);
            throw new BusinessException("批量提交水表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    @CacheEvict(value = "waterFee", allEntries = true)
    public boolean payWaterFee(Long billId, BigDecimal paymentAmount, String paymentMethod, LocalDateTime paymentTime) throws Exception {
        log.info("支付水费，账单ID: {}, 支付金额: {}, 支付方式: {}", billId, paymentAmount, paymentMethod);
        
        try {
            WaterFee fee = waterFeeMapper.selectById(billId);
            if (fee == null) {
                log.warn("水费记录不存在，ID: {}", billId);
                throw new BusinessException("水费记录不存在");
            }

            // 数据权限验证
            Long userId = SecurityUtils.getCurrentUserId();
            dataScopeService.hasCommunityPermission(userId, fee.getCommunityId());

            // 转换支付方式：字符串转换为整数值
            Integer paymentMethodCode = convertPaymentMethodToCode(paymentMethod);
            if (paymentMethodCode == null) {
                throw new BusinessException("不支持的支付方式: " + paymentMethod);
            }
            
            fee.setPaymentAmount(paymentAmount);
            fee.setPaymentMethod(paymentMethodCode);
            fee.setPaymentStatus(SystemStatusEnum.ENABLED.getCode()); // 1: 已支付
            fee.setPaymentTime(paymentTime);
            
            // 修复：同步更新已支付金额和未支付金额
            fee.setPaidAmount(paymentAmount); // 已支付金额设置为支付金额
            fee.setUnpaidAmount(BigDecimal.ZERO); // 未支付金额清零

            boolean result = waterFeeMapper.updateById(fee) > 0;
            log.info("水费支付完成，账单ID: {}, 结果: {}", billId, result);
            return result;
        } catch (Exception e) {
            log.error("支付水费失败", e);
            throw new BusinessException("支付水费失败");
        }
    }

    @Override
    @CacheEvict(value = "waterFee", allEntries = true)
    public int generateWaterFee(Long communityId, String billingPeriod, BigDecimal unitPrice) throws Exception {
        log.info("生成水费账单，社区ID: {}, 计费期间: {}, 单价: {}", communityId, billingPeriod, unitPrice);
        // fee_type=2 水费，已在SQL层强制，无需外部传递
        return waterFeeMapper.batchGenerateWaterFee(communityId, billingPeriod, unitPrice);
    }

    @Override
    @Cacheable(value = "abnormalUsage", key = "#communityId + ':' + #minUsage + ':' + #maxUsage", unless = "#result == null || #result.isEmpty()")
    public List<WaterFee> getAbnormalUsageRecords(Long communityId, BigDecimal minUsage, BigDecimal maxUsage) throws Exception {
        log.info("查询异常用量记录，社区ID: {}, 最小用量: {}, 最大用量: {}", communityId, minUsage, maxUsage);
        return waterFeeMapper.selectAbnormalUsageRecords(communityId, minUsage, maxUsage);
    }

    @Override
    @Cacheable(value = "waterFee", key = "'unpaid_user:' + #userId", unless = "#result == null || #result.isEmpty()")
    public List<WaterFee> getUnpaidWaterFeesByUserId(Long userId) throws Exception {
        log.info("查询用户未缴费水费账单，用户ID: {}", userId);
        return waterFeeMapper.selectUnpaidByUserId(userId);
    }

    @Override
    @Cacheable(value = "waterFee", key = "'statistics:' + #communityId + ':' + #year", unless = "#result == null")
    public Map<String, Object> getWaterFeeStatistics(Long communityId, Integer year) throws Exception {
        log.info("获取水费统计信息，社区ID: {}, 年份: {}", communityId, year);
        return waterFeeMapper.selectStatistics(communityId, year);
    }
    
    /**
     * 转换支付方式字符串为整数值
     * 
     * @param paymentMethod 支付方式字符串
     * @return 支付方式整数值，如果不支持则返回null
     */
    private Integer convertPaymentMethodToCode(String paymentMethod) {
        if (paymentMethod == null || paymentMethod.trim().isEmpty()) {
            return null;
        }
        
        PaymentMethodEnum methodEnum = PaymentMethodEnum.fromValue(paymentMethod.trim());
        return methodEnum != null ? methodEnum.getCode() : null;
    }
    
    // ==================== 移动端专用方法实现 ====================
    
    @Override
    @Cacheable(value = "waterFee", key = "'my_water_fees:' + #current + ':' + #size + ':' + #paymentStatus + ':' + #billingPeriod + ':' + T(com.smart.community.commons.utils.SecurityUtils).getCurrentUserId()", unless = "#result == null || #result.records.isEmpty()")
    public PageResult<WaterFeeVO> getMyWaterFees(Integer current, Integer size, 
                                                  Integer paymentStatus, String billingPeriod) throws Exception {
        log.info("开始查询当前用户的水费账单，当前页: {}, 每页大小: {}, 缴费状态: {}, 计费周期: {}", 
                current, size, paymentStatus, billingPeriod);
        
        // 获取当前登录用户ID
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取用户关联的房户ID集合（使用本地缓存）
        List<Long> householdIds = getUserHouseholdIds(currentUserId);
        if (householdIds.isEmpty()) {
            log.info("用户未关联任何房户，返回空结果，用户ID: {}", currentUserId);
            return PageResult.empty(current, size);
        }
        
        // 构建查询条件
        Page<WaterFee> page = new Page<>(current, size);
        QueryWrapper<WaterFee> wrapper = new QueryWrapper<>();
        wrapper.in("household_id", householdIds);
        
        if (paymentStatus != null) {
            wrapper.eq("payment_status", paymentStatus);
        }
        if (billingPeriod != null && !billingPeriod.trim().isEmpty()) {
            wrapper.eq("billing_period", billingPeriod);
        }
        
        // 添加去重逻辑：按房户ID、计费周期去重
        wrapper.groupBy("household_id", "billing_period");
        
        wrapper.orderByDesc("create_time");
        
        // 执行分页查询
        IPage<WaterFee> pageResult = this.page(page, wrapper);
        
        // 转换为VO
        List<WaterFeeVO> voList = pageResult.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        // 构建返回结果
        PageResult<WaterFeeVO> result = new PageResult<>();
        result.setRecords(voList);
        result.setTotal(pageResult.getTotal());
        result.setCurrent(current);
        result.setSize(size);
        result.setPages((int) pageResult.getPages());
        
        log.info("查询当前用户的水费账单成功，用户ID: {}, 总记录数: {}, 当前页记录数: {}", 
                currentUserId, result.getTotal(), voList.size());
        return result;
    }
    
    @Override
    @Cacheable(value = "waterFee", key = "'detail:' + #billId + ':' + #userId", unless = "#result == null")
    public WaterFeeVO getWaterFeeDetailForMobile(Long billId, Long userId) throws Exception {
        log.info("开始获取水费详情，账单ID: {}, 用户ID: {}", billId, userId);
        
        if (billId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "账单ID不能为空");
        }
        
        if (userId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取账单信息
        WaterFee waterFee = this.getById(billId);
        if (waterFee == null) {
            throw new BusinessException(ResultCode.DATA_NOT_FOUND, "账单不存在");
        }
        
        // 验证用户权限
        validateUserPermissionForFee(billId, userId);
        
        // 转换为VO
        WaterFeeVO result = convertToVO(waterFee);
        
        log.info("获取水费详情成功，账单ID: {}, 用户ID: {}", billId, userId);
        return result;
    }
    
    @Override
    public void validateUserPermissionForFee(Long feeId, Long userId) throws Exception {
        log.debug("开始验证用户权限，费用ID: {}, 用户ID: {}", feeId, userId);
        
        if (feeId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "费用ID不能为空");
        }
        
        if (userId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取费用信息
        WaterFee waterFee = this.getById(feeId);
        if (waterFee == null) {
            throw new BusinessException(ResultCode.DATA_NOT_FOUND, "费用记录不存在");
        }
        
        // 获取用户关联的房户ID集合（使用本地缓存）
        List<Long> householdIds = getUserHouseholdIds(userId);
        
        // 验证用户是否有权限访问该费用记录
        if (!householdIds.contains(waterFee.getHouseholdId())) {
            throw new BusinessException(ResultCode.PERMISSION_DENIED, "用户无权限访问该费用记录");
        }
        
        log.debug("用户权限验证通过，费用ID: {}, 用户ID: {}", feeId, userId);
    }
    
    /**
     * 转换为VO对象
     */
    private WaterFeeVO convertToVO(WaterFee waterFee) {
        if (waterFee == null) {
            return null;
        }
        
        WaterFeeVO vo = new WaterFeeVO();
        vo.setId(waterFee.getId());
        vo.setUserId(waterFee.getUserId());
        vo.setCommunityId(waterFee.getCommunityId());
        vo.setBuildingId(waterFee.getBuildingId());
        vo.setUnitId(waterFee.getUnitId());
        vo.setHouseholdId(waterFee.getHouseholdId());
        vo.setBillingPeriod(waterFee.getBillingPeriod());
        vo.setMeterNo(waterFee.getMeterNo());
        vo.setLastReading(waterFee.getLastReading());
        vo.setCurrentReading(waterFee.getCurrentReading());
        vo.setReadingDate(waterFee.getReadingDate());
        vo.setUsageAmount(waterFee.getUsageAmount());
        vo.setUnitPrice(waterFee.getUnitPrice());
        vo.setAmount(waterFee.getAmount());
        vo.setPaymentStatus(waterFee.getPaymentStatus());
        vo.setPaymentAmount(waterFee.getPaymentAmount());
        vo.setPaidAmount(waterFee.getPaidAmount());
        vo.setUnpaidAmount(waterFee.getUnpaidAmount());
        vo.setPaymentMethod(waterFee.getPaymentMethod());
        vo.setPaymentTime(waterFee.getPaymentTime());
        vo.setDueDate(waterFee.getDueDate());
        vo.setStatus(waterFee.getStatus());
        vo.setRemark(waterFee.getRemark());
        vo.setCreateTime(waterFee.getCreateTime());
        vo.setUpdateTime(waterFee.getUpdateTime());
        vo.setCreateBy(waterFee.getCreateBy());
        vo.setUpdateBy(waterFee.getUpdateBy());
        vo.setVersion(waterFee.getVersion());
        vo.setDeleted(waterFee.getDeleted());
        
        // 设置状态名称
        vo.setPaymentStatusName(getPaymentStatusName(waterFee.getPaymentStatus()));
        vo.setPaymentMethodName(getPaymentMethodName(waterFee.getPaymentMethod()));
        vo.setStatusName(getStatusName(waterFee.getStatus()));
        
        return vo;
    }
    
    /**
     * 获取支付状态名称
     */
    private String getPaymentStatusName(Integer paymentStatus) {
        if (paymentStatus == null) {
            return "未知";
        }
        switch (paymentStatus) {
            case 0:
                return "未支付";
            case 1:
                return "已支付";
            case 2:
                return "逾期";
            case 3:
                return "部分支付";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取支付方式名称
     */
    private String getPaymentMethodName(Integer paymentMethod) {
        if (paymentMethod == null) {
            return "未知";
        }
        switch (paymentMethod) {
            case 1:
                return "现金";
            case 2:
                return "微信";
            case 3:
                return "支付宝";
            case 4:
                return "银行卡";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) {
            return "未知";
        }
        switch (status) {
            case 0:
                return "禁用";
            case 1:
                return "启用";
            default:
                return "未知";
        }
    }
    
    // ========================= 辅助方法 =========================
    
    /**
     * 获取当前用户数据权限范围
     * @return 数据权限信息
     */
    private DataScopeInfo getCurrentUserDataScope() {
        try {
            return dataScopeService.getCurrentUserDataScope();
        } catch (Exception e) {
            log.warn("获取当前用户数据权限信息失败，可能是Feign接口调用或用户未登录: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 获取用户房户ID列表（带Spring Cache缓存）
     * @param userId 用户ID
     * @return 房户ID列表
     */
    @Cacheable(value = "userHousehold", key = "#userId", unless = "#result == null || #result.isEmpty()")
    private List<Long> getUserHouseholdIds(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }
        
        try {
            // 调用DataScopeService获取房户ID列表
            List<Long> householdIds = dataScopeService.getOwnerHouseholdIds(userId);
            if (householdIds != null) {
                // 同时更新本地缓存以保持兼容性
                userHouseholdCache.put(userId, householdIds);
                return householdIds;
            }
        } catch (Exception e) {
            log.warn("获取用户房户ID列表失败，用户ID: {}, 错误: {}", userId, e.getMessage());
        }
        
        return Collections.emptyList();
    }
    
}
